iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0
Modern Web

剛入行就一人重新打造公司前端系統?系列 第 24

Day 24 - useEffect 是拿來做什麼的?

  • 分享至 

  • xImage
  •  

useEffect 是拿來做什麼的?這件事在我初學 React 時其實相當困惑,就算知道它是React 中設計用來處理「副作用」的 hooks API 好了,但因為它會牽扯到很多很謎的情況,所以一直都覺得很難理解,像是:

  • 雖然知道 useEffect 是設計來處理「副作用」的,但是 ChatGPT 常常讓我利用 useEffect 來控制渲染的邏輯,這樣真的對嗎?
  • dependencies 的填法不一樣時,useEffect 的執行次數和時機也不同,到底該怎麼正確地填寫?
  • 沒用好可能會誤觸瘋狂重新渲染。

直到我看了《React 思維進化》這本書後,才真正理解 useEffect 的核心概念:它的主要功能是將資料的變更同步到副作用的執行中,並且 useEffect 的依賴陣列設計是用來進行效能優化。聽起來很抽象?接下來我會從頭開始說明的正確使用觀念。

副作用的介紹

什麼是副作用(effect)?

一個函式除了回傳結果外,還會與外部環境互動。像是修改函式外的全域變數、發送 API 請求或直接操作 DOM 元素等。

如果處理不當,會有什麼問題?

  • 效能問題:如果我們在元件內直接修改 DOM,會造成瀏覽器在元件渲染前等待 DOM 操作結束,會無法順暢更新畫面而導致卡頓或延遲。
  • 預期外的行為:多次 re-render 後,副作用會疊加,可能導致程式行為變得無法預測。

那在 React 中,可以利用 useEffect 來做副作用的管理。

useEffect 的語法與 dependencies 的填法

基本語法

useEffect(() => {
  // 副作用邏輯,例如:打 API 或更新 DOM
  return () => {
    // 清除副作用(可選),例如:取消訂閱或清理資源
  };
}, [dependencies]);
  • 參數
    • setup 函式:是一個函式,用於處理副作用邏輯。
      • cleanup 函式:如果 setup 函式返回一個函式,那麼這個返回的函式就稱為 cleanup。它會在元件卸載或依賴項變更前執行,用來清理副作用。
      • dependencies 發生變化時,setup 函式會被重新執行
    • dependencies:是一個陣列,是選填的,能夠決定什麼情況下重新執行副作用。

dependencies 的三種寫法

  1. 直接不寫:每次 render 後都會執行一次 setup 函式。
  2. 有填的話:React 會在 re-render 時以 Object.is 方法來一一比較陣列中所有依賴項目的值與前一次 render 時的版本是否相同,如果都相同的話則會跳過執行本次 render 的 setup 函式 。
  3. 放空陣列 [] :這個 setup 函式沒有任何的依賴資料,會被 React 認為在每次 re-render 時可以安全的跳過 setup 函式的執行。

所以 useEffect 是如何處理副作用的?

作法是元件 render 期間不進行副作用操作,因為副作用的執行可能會阻塞渲染流程,導致效能問題。因此,useEffect 在元件渲染完成後才執行。而且在重新執行副作用前,React 會先清理上一次的副作用,這樣就不會出現多次副作用重複執行、互相影響的情況。

React 的常見執行順序如下:

  1. 初次渲染:元件 render -> useEffect 執行 setup 函式。
  2. 依賴項變化或 component re-render
    • 先執行 cleanup 函式(如果有)。
    • 再執行 setup 函式(如果有變更的話)。
  3. 元件卸載:執行 cleanup 函式(如果有),清理之前的副作用。

也因為是這樣來處理副作用的,可以跑跑以下來看執行順序:

import { useState, useEffect } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log('副作用執行: 設置文件標題');
    document.title = `你點擊了 ${count} 次`;

    return () => {
      console.log('清理副作用: 重置標題');
      document.title = 'React App';
    };
  }, [count]); // 當 count 改變時,重新執行副作用

  return (
    <div>
      <p>你點擊了 {count} 次</p>
      <button onClick={() => setCount(count + 1)}>點擊我</button>
    </div>
  );
}

export default Counter;

參考資料


上一篇
Day 23 - 「元件」與 useState 使用技巧
下一篇
Day 25 - 寫 React 為何會觸發瘋狂的重新渲染?
系列文
剛入行就一人重新打造公司前端系統?31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言